
#include <string>
#include <iostream>

#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>


#include <thread>
#include <memory>
#include <functional>

#include <cstring>
#include <cstdlib>

void Usage(const std::string& s)
{
    std::cout<<"usage : ./"<< s<<"ip port\n";
}


const static int RetryCount = 5;
std::function<struct sockaddr*(void*)> conv= [](void* addr){
        return (struct sockaddr*)addr;
    };

bool visitServer(std::string& server_ip,uint16_t server_port)
{
    std::thread td;
        //1.创建套接字
    int sock= socket(AF_INET,SOCK_STREAM,0);

    
    if(sock<0)
    {
        std::cerr<<"socket error:"<<strerror(errno)<<std::endl;
        return false;
    }
    std::cout<<"create socket success , sock is:"<<sock<<"\n";

     

    //用智能指针的目的是处于释放socket的重复代码，如此只要函数结束，就能自动释放sock
    std::shared_ptr<void> ptr(nullptr,[&sock](void*){
        close(sock);
    });
    //客户端也是需要绑定ip和_sort，需要bind，但是不需要程序员手动操作

    struct sockaddr_in server;
    memset(&server,0,sizeof(server));
    inet_pton(AF_INET,server_ip.c_str(),&server.sin_addr);//字符串ip -> 字节ip
    server.sin_port = htons(server_port);
    server.sin_family = AF_INET;


    int n = connect(sock,conv(&server),sizeof(server));
    if(n<0)
    {
        std::cout<<"connect error\n";
        return false;
    }
    std::cout<<"connect Success\n";
    td  = std::thread([sock](){
            char buffer[1024];
            while(1)
            {
                int m = read(sock,buffer,sizeof(buffer));
                if(m>0)
                {
                    buffer[m] = 0; 
                    std::cout<<"Get a msg:"<<buffer<<"\n";
                }      
                else if(m==0)
                {
                    std::cout<<"任务结束\n";
                    exit(0);
                }      
                else
                { 
                    return -1;
                }
            }
            
        });
    td.detach();
    
    while(1)
    {
        std::string inbuffer;
        std::getline(std::cin,inbuffer);
        if(inbuffer=="quit")
        {
            break;
        }

        //write系统调用，如果输入数据，且接受端文件描述符直接关闭，OS直接干掉当前进程
        ssize_t n = write(sock,inbuffer.c_str(),inbuffer.size());
        if(n>0)
        {
            
        }
        else
        {
            return false;
        }
    }
    return 1;
}

int main(int argc,char* argv[])
{
    
    // if(argc!=3)
    // {
    //     Usage(argv[0]);
    //     return 1;
    // }
    // std::string server_ip = argv[1];
    // uint16_t server_port = std::stoi(argv[2]);
std::string server_ip = "127.0.0.1";
uint16_t server_port = std::stoi("8888");
    for(int i = 0;i<RetryCount;)
    {
       if(visitServer(server_ip,server_port))
       {
            break;
       }
       else{
            
            while(i<RetryCount && !visitServer(server_ip,server_port))
            {
                sleep(3);
                std::cout<<"server offline,retry connect ,count:"<<++i<<std::endl;
            }
            sleep(3);
            if(i < RetryCount)//对于短任务，我们自己成功一次退出就好
            {
                break;
            }
       }
    }

    return 0;
}